package stone926.mods.more_enchantments.blocks;

import net.minecraft.block.*;
import net.minecraft.entity.AreaEffectCloudEntity;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.effect.StatusEffect;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.entity.passive.VillagerEntity;
import net.minecraft.fluid.FluidState;
import net.minecraft.fluid.Fluids;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.particle.DustParticleEffect;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.predicate.entity.EntityPredicates;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.state.StateManager;
import net.minecraft.state.property.BooleanProperty;
import net.minecraft.state.property.Properties;
import net.minecraft.util.math.*;
import net.minecraft.world.BlockView;
import net.minecraft.world.World;
import net.minecraft.world.WorldAccess;
import net.minecraft.world.WorldView;
import stone926.mods.more_enchantments.MoreEnchantmentsMod;
import stone926.mods.more_enchantments.damage.StoneDamageSource;
import stone926.mods.more_enchantments.interfaces.IEntitySpawnedByFlower;
import stone926.mods.more_enchantments.interfaces.ILivingEntity;
import stone926.mods.more_enchantments.interfaces.ILogCooldown;
import stone926.mods.more_enchantments.util.BlockUtil;
import stone926.mods.more_enchantments.util.Logger;
import stone926.mods.more_enchantments.util.RandomUtil;

import java.util.List;
import java.util.Random;

import static stone926.mods.more_enchantments.MoreEnchantmentsMod.BLACK_MANDALA_SPAWNING;
import static stone926.mods.more_enchantments.MoreEnchantmentsMod.CORNEL_ACTIVE;

public class CornelFlowerBlock extends FlowerBlock implements Fertilizable, Waterloggable {

  public static final BooleanProperty WATERLOGGED = Properties.WATERLOGGED;

  public CornelFlowerBlock(StatusEffect suspiciousStewEffect, int effectDuration, Settings settings) {
    super(suspiciousStewEffect, effectDuration, settings);
    this.setDefaultState(getDefaultState().with(WATERLOGGED, false));
  }

  @Override
  public void randomDisplayTick(BlockState state, World world, BlockPos pos, Random random) {
    super.randomDisplayTick(state, world, pos, random);
    RandomUtil.runIfPossible(0.1, random, () -> {
      world.addParticle(
        new DustParticleEffect(new Vec3f(0.965F, 0.5926F, 0.0549F), 1 + random.nextInt(3)),
        pos.getX() + 0.5,
        pos.getY() + random.nextFloat(),
        pos.getZ() + 0.5,
        0, 0.3, 0
      );
    });
  }

  @Override
  public void onEntityCollision(BlockState state, World world1, BlockPos pos, Entity entity) {
    super.onEntityCollision(state, world1, pos, entity);
    if (world1.getGameRules().getBoolean(CORNEL_ACTIVE)) {
      ILogCooldown logEntity = (ILogCooldown) entity;
      if (world1 instanceof ServerWorld world) {
        Logger<ServerWorld> logger = new Logger<>(
          world, MoreEnchantmentsMod.LOGGER, BlockUtil.SHOULD_FLOWER_LOG.test(world) && logEntity.canCornelLog()
        );
        if (entity instanceof LivingEntity livingEntity && ((ILivingEntity) livingEntity).canHealedByCornel()) {
          LivingEntity attacker = livingEntity.getAttacker();
          if (attacker != null && ((IEntitySpawnedByFlower) attacker).isSpawnedByMandala()) {
            if (livingEntity.getHealth() <= livingEntity.getMaxHealth() / 5F) {
              int cooldown = 80 + world.random.nextInt(31);
              logger.log(Logger.getBlockDesc(pos, "CornelBlock")
                               .append(" heals ")
                               .append(Logger.getEntityDesc(livingEntity))
                               .append(" and set heal cooldown: ")
                               .append(cooldown));
              logEntity.setCornelLogCooldown(40);
              livingEntity.heal(livingEntity.getMaxHealth());
              ((ILivingEntity) livingEntity).setHealedByCornelCooldown(cooldown);
            }
          }
        }
        if (((IEntitySpawnedByFlower) entity).isSpawnedByMandala() && world.random.nextInt(4) == 0) {
          logger.logBegin(Logger.getBlockDesc(pos, "CornelBlock")
                                .append(" weakens ")
                                .append(Logger.getEntityDesc(entity)));
          entity.slowMovement(state, new Vec3d(0.5, 0, 0.5));
          logger.logContent("slows movement of " + Logger.getEntityDesc(entity));
          int i = world.random.nextInt(3);
          StatusEffect weakness = StatusEffects.WEAKNESS;
          StatusEffectInstance instance = new StatusEffectInstance(weakness, 2, i, true, false);
          if (entity instanceof LivingEntity livingEntity) {
            boolean b = livingEntity.addStatusEffect(instance);
            if (b) {
              logger.logContent(
                new StringBuilder()
                  .append("add ").append(Logger.getEffectDesc(instance))
                  .append(" to ").append(Logger.getEntityDesc(livingEntity))
              );
            }
          }
          logger.logEnd("", false);
          logEntity.setCornelLogCooldown(40);
        }
      }
    }
  }

  @Override
  public void randomTick(BlockState state, ServerWorld world, BlockPos pos, Random random) {
    super.randomTick(state, world, pos, random);
    if (world.getGameRules().getBoolean(CORNEL_ACTIVE)) {
      Logger<ServerWorld> logger = new Logger<>(world, MoreEnchantmentsMod.LOGGER, BlockUtil.SHOULD_FLOWER_LOG, world);
      if (world.getGameRules().getBoolean(BLACK_MANDALA_SPAWNING)) {
        int bx = pos.getX();
        int by = pos.getY();
        int bz = pos.getZ();
        List<LivingEntity> livingEntities = world
          .getEntitiesByClass(
            LivingEntity.class, Box.from(new Vec3d(bx, by, bz)).expand(10, 3, 10), EntityPredicates.VALID_LIVING_ENTITY
          )
          .stream()
          .filter(e -> ((IEntitySpawnedByFlower) e).isSpawnedByMandala())
          .filter(e -> !(e instanceof VillagerEntity))
          .toList();

        logger.logBegin(Logger.getBlockDesc(pos, "CornelBlock").append(" trying to kill nearby entities"));
        logger.logContent("finding nearby entities");

        int killedEntityCount = 0;
        if (!livingEntities.isEmpty()) {
          world.spawnParticles(
            new DustParticleEffect(new Vec3f(0.964F, 0.5925F, 0.0548F), 1 + random.nextInt(3)),
            bx + 0.5, by + 3, bz + 0.5,
            250, 0.2, 6, 0.2,
            0.5
          );
          int i = 6 + random.nextInt(12);
          for (LivingEntity livingEntity : livingEntities) {
            double x = livingEntity.getX();
            double y = livingEntity.getY() + livingEntity.getHeight();
            double z = livingEntity.getZ();
            world.spawnParticles(ParticleTypes.ANGRY_VILLAGER, x, y, z, 10, 0.22, 0.4, 0.22, 0.3);
            kill(livingEntity);
            logger.logContent(new StringBuilder().append("kills ").append(Logger.getEntityDesc(livingEntity)));
            killedEntityCount++;
            if (killedEntityCount >= i) break;
          }

        } else {
          logger.logContent("failed to find nearby entities");
        }
        logger.logEnd("totally killed " + killedEntityCount + " entities", true);

        logger.logBegin(Logger.getBlockDesc(pos, "CornelBlock").append(" trying to clear nearby AreaEffectCloud"));
        List<AreaEffectCloudEntity> effectCloudEntities = world.getEntitiesByClass(
          AreaEffectCloudEntity.class,
          Box.from(new Vec3d(bx, by, bz)).expand(5, 3, 5),
          EntityPredicates.VALID_ENTITY
        );
        int count = 0;
        if (!effectCloudEntities.isEmpty()) {
          for (AreaEffectCloudEntity areaEffectCloudEntity : effectCloudEntities) {
            LivingEntity owner = areaEffectCloudEntity.getOwner();
            if (owner != null) {
              if (((IEntitySpawnedByFlower) owner).isSpawnedByMandala()) {
                logger.log(new StringBuilder().append("clear ").append(Logger.getEntityDesc(areaEffectCloudEntity)));
                areaEffectCloudEntity.kill();
                count++;
              }
            }
          }
        } else {
          logger.logContent("failed");
        }
        logger.logEnd("totally clear " + count + " AreaEffectCloudEntity", true);

      }

      if (random.nextInt(50) == 0) {
        int cnt = 0;
        logger.logBegin(Logger.getBlockDesc(pos, "CornelBlock").append(" trying to break nearby BlackMandalaBlock"));
        for (BlockPos p : BlockPos.iterate(pos.add(-5, -2, -5), pos.add(5, 2, 5))) {
          if (RandomUtil.isPossible(0.2, world.getRandom())) {
            if (world.getBlockState(p).isOf(MoreEnchantmentsMod.BLACK_MANDALA)) {
              if (world.breakBlock(p, true)) {
                cnt++;
                logger.logContent(Logger.getBlockDesc(p, "BlackMandalaBlock").append(" is broken"));
              }
            }
          }
        }
        logger.logEnd("totally broke " + cnt + " blocks", true);
      }

      if (random.nextInt(400) == 0) {
        logger.log(Logger.getBlockDesc(pos, "CornelBlock").append(" tries to grow"));
        ((Fertilizable) this).grow(world, random, pos, state);
      }
    }
  }

  private void kill(LivingEntity livingEntity) {
    ((ILivingEntity) livingEntity).setDropsNothing(true);
    ((ILivingEntity) livingEntity).forceDamage(StoneDamageSource.CORNEL, Integer.MAX_VALUE);
  }

  @Override
  protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
    super.appendProperties(builder);
    builder.add(WATERLOGGED);
  }

  public BlockState getStateForNeighborUpdate(BlockState state, Direction direction, BlockState neighborState, WorldAccess world, BlockPos pos, BlockPos neighborPos) {
    if (state.get(WATERLOGGED)) {
      world.createAndScheduleFluidTick(pos, Fluids.WATER, Fluids.WATER.getTickRate(world));
    }
    return super.getStateForNeighborUpdate(state, direction, neighborState, world, pos, neighborPos);
  }

  public FluidState getFluidState(BlockState state) {
    return state.get(WATERLOGGED) ? Fluids.WATER.getStill(false) : super.getFluidState(state);
  }

  public BlockState getPlacementState(ItemPlacementContext ctx) {
    FluidState fluidState = ctx.getWorld().getFluidState(ctx.getBlockPos());
    return this.getDefaultState().with(WATERLOGGED, fluidState.getFluid() == Fluids.WATER);
  }

  @Override
  public boolean canPlaceAt(BlockState state, WorldView world, BlockPos pos) {
    return super.canPlaceAt(state, world, pos)
      || BlockUtil.mandalaAndCornelCanPlaceAt(state, world, pos)
      || state.isOf(MoreEnchantmentsMod.BLACK_MANDALA);
  }

  @Override
  public boolean isFertilizable(BlockView world, BlockPos pos, BlockState state, boolean isClient) {
    return false;
  }

  @Override
  public boolean canGrow(World world, Random random, BlockPos pos, BlockState state) {
    return false;
  }

  @Override
  public void grow(ServerWorld world, Random random, BlockPos pos, BlockState state) {}

}
